package com.qf;

import com.qf.factorybean.MyFactoryBean;
import com.qf.pojo.Student;
import com.qf.pojo.User;
import com.qf.service.UserService;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import java.sql.Connection;

/**
 * @author lwc
 * @date 2021/10/26 16:33
 * @Description ：
 *
 *IOC的思想 基于IOC容器的，IOC容器的底层就是 对象工厂
 * spring 提供IOC容器的方式有多种
 * 1.BeanFactory  IOC容器的基本实现 这个接口是spring 内部自己使用的接口，开发人员不使用
 * 这个容器不是在 加载配置文件的时候 创建bean对象，而是在获取bean对象的时候才创建【懒加载】
 *
 * 2.ApplicationContext 是BeanFactory的子接口 提供了更强大的功能，这个接口是给开发人员来使用的
 * 这个容器是在加载配置文件的时候就会创建bean对象
 *
 * 3.真正干活的不是接口，必然是实现类 常用的实现类
 *          ClassPathXmlApplication 是ApplicationContext的实现类 基于解析xml文件的方式的容器
 *          AnnotationConfigApplicationContext 是ApplicationContext的实现类 基于解析注解的方式的容器
 *
 * IOC相关的概念 Inversion of Control
 *  控制反转 把对象的创建和对象之间的调用过程 交给spring容器来管理
 *  使用ioc的目的 ：降低耦合度
 *
 *  案例：
 *      spring容器管理bean的步骤
 *      1.spring创建bean对象
 *      2.给bean对象注入属性
 *          set 方法的形式 注入属性
 *              定义User类 在类中指定属性的set方法
 *              在配置文件 通过property给属性赋值
 *           构造方法的实现方式 注入属性
 *    bean的管理的实现方式： 基于xml配置文件的方式实现，基于注解，基于配置类
 *
 *    bean的作用域 scope
 *         在spring容器中设置bean是单例还是多例  < bean scope="singleton | prototype" />
 *
 *         singleton（默认）:每次调用工厂，得到的都是同一个对象。加载spring配置文件时候就会创建单势力对象
 *
 *         prototype：每次调用工厂，都会创建新的对象。不是在加载spring配置文件时候创建对象，在调用getBean方法时候创建多实例对象
 *
 */
public class TestSpringIocFactory {

    //测试beans1.xml
    // 利用ref来判断用那个dao
    @Test
    public void test1(){
    //1.加载spring配置文件 创建容器 容器已经把要管理的bean 创建好了
    //    底层就是读取配置文件 或者 配置类 或者 注解 通过反射的方式 创建对象 放在容器中
        ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("classpath:beans1.xml");

        //从容器得到对象 不是自己创建的 IOC 对象的创建和维护 不是程序员自己做的，交给容器来做

        UserService userService = classPathXmlApplicationContext.getBean("userService", UserService.class);

        userService.save();

    }

    //测试的beans2.xml中的set方法注入属性
    @Test
    public void test2(){

        //set 方法注入属性
        //后面的路径别忘了写
        ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:beans2.xml");

        //从容器得到对象 不是自己创建的 IOC对象的创建喝维护 不是程序员自己做的，交给容器来做
        User user = applicationContext.getBean("user", User.class);
        Student student = applicationContext.getBean("student", Student.class);
        System.out.println(user);
        System.out.println(student);
    }

    //构造方法注入属性
    @Test
    public void  test3(){
        ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:beans2.xml");

        //从容器得到对象 不是自己创建的

        User user = applicationContext.getBean("user2", User.class);
        System.out.println(user);
    }
    //测试beans3.xml
    //通过byType或者来byName 来决定用那个dao
    @Test
    public void test4(){
        //自动注入
        ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:beans3.xml");

        UserService userService = applicationContext.getBean("userService", UserService.class);
        userService.save();

    }

    //测试的是beans4.xml
    @Test
    public void  test5(){
        //prototype多例 singleton单例
        //在spring 容器中 默认情况下bean是单例的 单例bean和单例模式不一样
        //单例模式是整个jvm进程中 只有一个这个单例对象，单例bean是和容器绑定的
        //一个jvm进程 可以有多个容器 所有可以有多个单例bean对象

        ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:beans4.xml");

       UserService userService = applicationContext.getBean("userService", UserService.class);
        UserService userService1 = applicationContext.getBean("userService", UserService.class);

        System.out.println(userService==userService1);

        System.out.println(userService);
        System.out.println(userService1);


    }
    //测试beans5.xml
    @Test
    public void  test6(){
        //FactoryBean  是一种特殊的bean，这个bean 用来产出一些复杂的bean 交给spring容器来管理
        //在id面前追加& 意思是创建一个FactoryBean的实现类对象
        ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:beans5.xml");

        Connection connection = applicationContext.getBean("mb", Connection.class);

        MyFactoryBean myFactoryBean = applicationContext.getBean("&mb", MyFactoryBean.class);

        System.out.println(connection);
        System.out.println(myFactoryBean);
    }
    @Test
    public void test7(){
        ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:beans6.xml");

        User user = applicationContext.getBean("user", User.class);

        System.out.println("第四步 获得bean");
        System.out.println(user);
        applicationContext.close();
    }

}
